package edu.hawaii.halealohacli.command;

import java.io.IOException;
import java.io.InputStream;
import java.util.Timer;
import java.util.TimerTask;

/**
 * A command that repeatedly executes according to a given time internal
 * until it is interrupted by the user.  A Command can either extends this
 * class or create an instance of it.
 * 
 * @author Zach Tomaszewski
 */
public abstract class RepeatedCommand {
  
  //package-private for testing purposes
  static Timer jobs = new Timer();
  InputStream input = System.in;  

  /**
   * Causes this command to repeatedly invoke the {@link #doTask()}doTask()
   * method with a delay of the given number of seconds between
   * each invocation.  This method blocks until the user provides
   * input, which ends execution of this method.  doTask() should
   * generally result in some output for the user to see.  
   * 
   * @param secondsInterval  The delay (in seconds) between iterations.
   *                      Any value less than 0 is treated as 0.
   */
  public void execute(int secondsInterval) {
    int interval = (secondsInterval >= 0) ? secondsInterval : 0;
    
    //anonymous class 
    TimerTask task = new TimerTask() {
      @Override
      public void run() {
        RepeatedCommand.this.doTask(); 
      }        
    };
    
    //start the task iterating...
    jobs.scheduleAtFixedRate(task, 0, interval * 1000);

    //wait for user input, checking every 1/2 second...
    try {
      while (input.available() == 0) {
        try {
          Thread.sleep(200);
        }
        catch (InterruptedException e) {
          //someone else woke us up.  See if any input, otherwise go back to sleep 
        }
      }
    }
    catch (IOException e) {  
      //problem with System.in, so better quit so as not to infinitely loop
      System.out.println("Problem with input stream... Terminating early.");
    }
        
    task.cancel();  //kill the task
    try {
      //Because it connects to a server, the task can take a while.  
      //So give it a bit of time to actually quit so that it doesn't execute after
      //returning to the input prompt
      Thread.sleep(200);  
    }
    catch (InterruptedException e) {
      //okay... guess we won't wait.  No worries.
    }

    //clear input
    try {
      while (input.available() > 0) {
        input.read();
      }
    }
    catch (IOException e) {  //NOPMD: empty
      //oops: couldn't clear it.  Oh well, not a big deal 
    }
  }
  
  /**
   * A subclass should override this method to provide the behavior
   * that should be repeated every few seconds by this command.
   */
  public abstract void doTask();
  
  /**
   * Terminates any currently repeating jobs.
   * This is usually necessary when the application quits to kill the Timer
   * thread.  Once called, no more repeating jobs may be started.
   */
  public static void terminateAll() {
    jobs.cancel();
  }
}
